#include "StdAfx.h"

WMOModel::WMOModel(std::string szFile, MODF m) : ModelBase(2), m_spawnInfo(m)
{
	m_lastUpdate = GetTickCount();
	m_fileName = szFile;
	m_translation[0] = m_translation[1] = m_translation[2] = 0.0f;
	m_rotation[0] = m_rotation[1] = m_rotation[2] = 0.0f;
}

bool WMOModel::Init()
{
	m_file = new CMpqFile(m_fileName);
	if(!m_file->IsOpened())
	{ 
		delete m_file;
		m_file = 0;
		return false;
	}

	ui32 sig = 0;
	ui32 len = 0;
	while(LoadChunk(sig, len))
	{
		switch(sig)
		{
		case 0x4D4F4844:
			{
				m_file->ReadInc(sizeof(WMOHeader), &m_header);
				break;
			}
		case 0x4D4F5458:
			{
				LoadTextures(len);
				break;
			}
		case 0x4D4F4D54:
			{
				LoadMaterials();
				break;
			}
		case 0x4D4F474E:
			{
				LoadGroupNames(len);
				break;
			}
		case 0x4D4F4749:
			{
				LoadGroupInfo();
				break;
			}
		case 0x4D4F4C54:
			{
				LoadLights();
				break;
			}
		case 0x4D4F4453:
			{
				LoadSets();
				break;
			}
		case 0x4D4F444E:
			{
				LoadDoodads(len);
				break;
			}
		case 0x4D4F4444:
			{
				LoadDoodadInfos();
				break;
			}
		default:
			m_file->ModInc(len);
			break;
		}
	}

	for(ui32 i = 0; i < m_header.nGroups; ++i)
	{
		WMOGroup* grp = new WMOGroup(m_fileName, i, this);
		grp->Init();
		m_groups.push_back(grp);
		sD3D.getTaskMgr().pushTask(grp);
	}
	sD3D.AddMesh(this);
	return true;
}

ui32 WMOModel::LoadChunk(ui32& sig, ui32& len)
{
	if(!m_file)
		return ui32(-1);
	sig = 0;
	m_file->ReadInc(4, &sig);
	if(sig == 0)
		return 0;
	m_file->ReadInc(4, &len);
	if(len == 0)
		return 1;
	if(m_file->TellInc() + len > m_file->GetSize())
		return 0;
	return 1;
}

void WMOModel::Draw(Vertex3F pos, Vertex3F tar)
{
	Vertex3F front(tar.x - pos.x, tar.y - pos.y, tar.z - pos.z);
	Vertex3F target(m_translation[0] - pos.x, m_translation[1] - pos.y, m_translation[2] - pos.z);
	Vertex3F target2D(m_translation[0] - pos.x, 0.0f, m_translation[2] - pos.z);	
	float angle = acos((front.x * target.x + front.z * target.z + front.y * target.y) / (front.Length() * target.Length()));
	if((angle * 180 / M_PI > 50 && target2D.Length() > CHUNKSIZE))
		return;

	float radius = sqrtf(powf(pos.x - m_translation[0], 2.0f) + powf(pos.z - m_translation[2], 2.0f));
	if(radius > fogDistance + 0.2f * TILESIZE)
		return;

	if(!sD3D.ShouldRender(m_spawnInfo))
		return;

	IDirect3DDevice9* pDev = sD3D;
	pDev->SetRenderState(D3DRS_ALPHABLENDENABLE, D3DZB_TRUE);
	pDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	pDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

	D3DXMATRIX matTrans, matRot, matRotX, matRotY, matRotZ;
	D3DXMatrixTranslation(&matTrans, m_translation[0], m_translation[1], m_translation[2]);
	D3DXMatrixRotationX(&matRotX, /*D3DXToRadian*/(m_rotation[0]));
	D3DXMatrixRotationY(&matRotY, /*D3DXToRadian*/(m_rotation[1]));
	D3DXMatrixRotationZ(&matRotZ, /*D3DXToRadian*/(m_rotation[2]));
	matRot = matRotX * matRotY * matRotZ;
	matTrans = matRot * matTrans;
	//sD3D->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

	pDev->SetTransform(D3DTS_WORLD, &matTrans);

	for(ui32 i = 0; i < m_groups.size(); ++i)
		m_groups[i]->Draw();

	pDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	pDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
	pDev->SetTransform(D3DTS_WORLD, &matID);
}

void WMOModel::LoadTextures(ui32 size)
{
	ui32 counter = 0;
	std::string curtex;
	bool seeking_align = false; // the names are aligned to 4 byte addresses (0x00 0x04 0x08 0x0C)
	ui32 curstart = 0;
	while(true)
	{
		++counter;
		char c = 0;
		m_file->ReadInc(1, &c); // yes, its sick to read every char, but theres no other way...
		if(!seeking_align) // were reading a texturename
		{
			curtex.push_back(c);
			if(c == 0) // string finished
			{
				m_textures[curstart] = curtex; // add texture
				curtex.clear(); // new texturename
				seeking_align = true; // we need to realign!
			}
		}
		else
		{
			if(((counter - 1) % 4) == 0) // counter on the right place
			{
				if(c != 0) // sometimes there are empty alignements. so just restart reading textures if not
				{
					curtex.push_back(c);
					seeking_align = false; // we have found it!! :D
					curstart = counter - 1;
				}
			}
		}
		if(counter >= size)
			break;
	}
}

void WMOModel::LoadMaterials()
{
	WMOMaterial mat;
	for(ui32 i = 0; i < m_header.nMaterials; ++i)
	{
		m_file->ReadInc(sizeof(WMOMaterial), &mat);
		m_materials.push_back(mat);
		m_texids.push_back(CTextureHandler::GetInstance()->GetTexture(m_textures[mat.ofsTexture_1]));
	}
}

void WMOModel::LoadGroupNames(ui32 size)
{
	std::string curname;
	for(ui32 i = 0; i < size; ++i)
	{
		char c = 0;
		m_file->ReadInc(1, &c);
		curname.push_back(c);
		if(c == 0)
		{
			m_groupnames.push_back(curname);
			curname.clear();
		}
	}
}

void WMOModel::LoadGroupInfo()
{
	WMOGroupInfo inf;
	for(ui32 i = 0; i < m_header.nGroups; ++i)
	{
		m_file->ReadInc(sizeof(WMOGroupInfo), &inf);
		m_groupinfos.push_back(inf);
	}
}

void WMOModel::LoadLights()
{
	WMOLight li;
	for(ui32 i = 0; i < m_header.nLights; ++i)
	{
		m_file->ReadInc(sizeof(WMOLight), &li);
		m_lights.push_back(li);
	}
}

void WMOModel::LoadSets()
{
	WMODoodadSet set;
	for(ui32 i = 0; i < m_header.nSets; ++i)
	{
		m_file->ReadInc(sizeof(WMODoodadSet), &set);
		m_sets.push_back(set);
	}
}

void WMOModel::LoadDoodads(ui32 size)
{
	ui32 counter = 0;
	std::string curtex;
	bool seeking_align = false; // the names are aligned to 4 byte addresses (0x00 0x04 0x08 0x0C)
	ui32 curstart = 0;
	while(true)
	{
		++counter;
		char c = 0;
		m_file->ReadInc(1, &c); // yes, its sick to read every char, but theres no other way...
		if(!seeking_align) // were reading a modelname
		{
			curtex.push_back(c);
			if(c == 0) // string finished
			{
				m_doodads[curstart] = curtex; // add name
				curtex.clear(); // new texturename
				seeking_align = true; // we need to realign!
			}
		}
		else
		{
			if(((counter - 1) % 4) == 0) // counter on the right place
			{
				if(c != 0) // sometimes there are empty alignements. so just restart reading names if not
				{
					curtex.push_back(c);
					seeking_align = false; // we have found it!! :D
					curstart = counter - 1;
				}
			}
		}
		if(counter >= size)
			break;
	}
}

void WMOModel::LoadDoodadInfos()
{
	WMODoodadInfo inf;
	for(ui32 i = 0; i < m_header.nDoodads; ++i)
	{
		m_file->ReadInc(sizeof(WMODoodadInfo), &inf);
		m_doodadinfos.push_back(inf);
	}
}